package cn.tedu.http;

import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Author：程Sir
 * Name： SmallServer
 * Content:
 * HttpResponse : 是响应对象
 * 当前类的每一个示例对象都用来表示给客户端发送一个HTTP的响应
 * 有三部分组成：
 *      状态行、响应头。、响应正文
 */
public class HttpResponse {
    /*
        状态行信息
     */
    private int statusCode=200; // 默认是200，表示资源是存在的！
    private String statuseReason = "GOOD!";
    /*
        响应头信息：
     */
    private Map<String,String> headers = new HashMap<>();

    public void putHaeders(String name, String value ){
        headers.put(name,value);
    }
    /*
        响应正文信息
     */
    private File fileEntity;

    /**
     * 响应正文
     * 目前所有的请求处理，都是按文件进行反馈的，
     * 而Content-Type 和 Content-Length都是对响应正文的描述，
     * 所以是可以跟着响应正文一起发送过去的！
     * @param file
     */
    public void setFileEntity(File file){
        fileEntity = file;
        /*
            下面进行响应正文信息的展示
         */
        // 1.现获取文件的名称
        String name = file.getName();
        // 2.通过名称获取后缀
        String type = name.substring(name.lastIndexOf(".")+1); // html
        // 3.通过拿到的后缀名找对应的mime类型
        String text = HttpContext.getMimeType(type);

        // 给响应头设置指定的类型【至此，Headers集合中就已经有值了，只就是需要响应给客户端的】
        putHaeders("Content-Type",text);
        putHaeders("Content-Length",file.length()+"");
    }

    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public void setStatuseReason(String statuseReason) {
        this.statuseReason = statuseReason;
    }

    public String getStatuseReason() {
        return statuseReason;
    }

    public File getFileEntity() {
        return fileEntity;
    }

    private Socket socket;

    public HttpResponse(Socket socket){
        this.socket = socket;
    }


    /**
     * 统一管理发送状态行、响应头、响应正文的方法
     */
    public void flush(){
        sendStatusLine();
        sendHeaders();
        sendContent();
    }

    // 1. 发送状态行
    private void sendStatusLine(){
        System.out.println("=============开始发送状态行...");

        // 1.状态行内容
        String line="HTTP/1.1 "+ statusCode + " " + statuseReason;
        println(line);
        System.out.println("=============状态行发送完毕！");

    }

    // 2. 发送响应头
    private void sendHeaders(){
        System.out.println("=============开始发送响应头信息...");
        // 2.响应头内容
        // 遍历设置好的响应头集合信息
        Set<Map.Entry<String, String>> entries = headers.entrySet();
        for (Map.Entry<String, String> m : entries){
            String key = m.getKey();  // 响应头名称
            String value = m.getValue(); // 响应头的值
            String line = key+": "+value;
            println(line);
        } // 还可以使用lambda表达式来撰写



        // 响应头信息全部发送完毕的标识是：单独发生一个连续的字符标识CRLF
//           outputStream.write(13); // CR
//           outputStream.write(10); // LF
        println(""); // 单独发生CRLF表示响应头部分发生完毕！
        System.out.println("=============响应头信息发送完毕！");
    }
    // 3. 发送响应正文
    private void sendContent(){
        System.out.println("=============开始发送响应正文...");
        try (FileInputStream fileInputStream = new FileInputStream(fileEntity)){
            //3. 响应正文
            // 创建文件输入流读取要发生给客户端的资源数据

            byte[] buf = new byte[5 * 1024];
            // 定义一个表示符：每次读取的字节数
            int len;
            while ((len= fileInputStream.read(buf)) !=-1){
                OutputStream outputStream = socket.getOutputStream();
                // 将读到的数据写出
                outputStream.write(buf,0,len);
            }
            System.out.println("=============响应正文发生完毕！");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 写出一行数据
     * @param line 需要被写出一行字符串
     */
    private void println(String line){
        try {
            OutputStream outputStream = socket.getOutputStream();
            byte[] bytes = line.getBytes("ISO8859-1");
            outputStream.write(bytes);
            outputStream.write(13); // CR
            outputStream.write(10); // LF
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
